<template>
  <div>
    <canvas
      :id="radom"
      :class="{canDraw: 'canvas'}"
      :width="width"
      :height="height"
      :style="{'width':`${width}px`,'height':`${height}px`}"
      @mousedown="canvasDown($event)"
      @mouseup="canvasUp($event)"
      @mousemove="canvasMove($event)"
      @touchstart="canvasDown($event)"
      @touchend="canvasUp($event)"
      @touchmove="canvasMove($event)"
      @dblclick="canvasDbClick($event)"
      @click="canvasClick($event)"
    ></canvas>
    <canvas
      id="oriCanvas"
      :width="width"
      :height="height"
      :style="{'width':`${width}px`,'height':`${height}px`}"
    ></canvas>
    <input type="text" id="input" placeholder="请输入" />
  </div>
</template>
<script>
import html2Canvas from 'html2canvas'
const uuid = require('node-uuid')
export default {
  props: {
    canDraw: { // 图片路径
      type: Boolean,
      default: true
    },
    url: { // 图片路径
      type: String
    },
    info: { // 位置点信息
      type: Array
    },
    width: { // 绘图区域宽度
      type: String
    },
    height: { // 绘图区域高度
      type: String
    },
    lineColor: { // 画笔颜色
      type: String,
      default: 'red'
    },
    lineWidth: { // 画笔宽度
      type: Number,
      default: 2
    },
    lineType: { // 画笔类型
      type: String,
      default: 'circle',
    }
  },
  watch: {
    lineType (val) {
      if (val) {
        if (val === 'cancel') {
          this.clearDraw()
        } else if (val === 'save') {
          this.downloadIamge()
        }
      }
    },
    info (val) {
      if (val) {
        this.initDraw()
      }
    }
  },
  data () {
    return {
      // 同一页面多次渲染时，用于区分元素的id
      radom: uuid.v4(),
      // canvas对象
      context: {},
      // 是否处于绘制状态
      canvasMoveUse: false,
      // 绘制矩形和椭圆时用来保存起始点信息
      beginRec: {
        x: '',
        y: '',
        imageData: ''
      },
      // 储存坐标信息
      drawInfo: [],
      // 背景图片缓存
      img: new Image()
    }
  },
  mounted () {
    this.initDraw()
  },
  methods: {
    // 初始化绘制信息
    initDraw () {
      // 初始化画布
      const canvas = document.getElementById(this.radom)
      var oriCanvas = document.getElementById("oriCanvas");
      this.context = canvas.getContext('2d')
      this.contextOri = oriCanvas.getContext("2d");
      // 初始化背景图片
      this.img.setAttribute('crossOrigin', 'Anonymous')
      this.img.src = this.url
      this.img.onerror = () => {
        var timeStamp = +new Date()
        this.img.src = this.url + '?' + timeStamp
      }
      this.img.onload = () => {
        this.clean()
      }
      // 初始化画笔
      this.context.lineWidth = this.lineWidth
      this.context.strokeStyle = this.lineColor
    },
    canvasClick (e) {
      var input = document.getElementById('input')
      input.style.display = 'none'
      input.value = ""
    },
    canvasDbClick (e) {
      let canvasX = e.clientX - e.target.parentNode.offsetLeft
      let canvasY = e.clientY - e.target.parentNode.offsetTop
      var context = this.context
      console.log(canvasX)
      console.log(canvasY)
      if (this.lineType === 'text') {
        var input = document.getElementById('input')
        input.style.display = 'block'
        input.style.top = canvasY + 'px'
        input.style.left = canvasX + 'px'
        input.onkeydown = function (e) {
          var evt = window.event || e;
          if (evt.keyCode == 13) {
            context.fillStyle = "white";
            context.fillText(input.value, canvasX, canvasY);
            input.onblur()
          }
        }
        input.onblur = function (a) {
          input.style.display = 'none'
          input.value = ""
        }
      }
    },
    // 鼠标按下
    canvasDown (e) {
      if (this.canDraw) {
        this.canvasMoveUse = true
        // client是基于整个页面的坐标，offset是cavas距离pictureDetail顶部以及左边的距离
        const canvasX = e.clientX - e.target.parentNode.offsetLeft
        const canvasY = e.clientY - e.target.parentNode.offsetTop
        // 记录起始点和起始状态
        this.beginRec.x = canvasX
        this.beginRec.y = canvasY
        this.beginRec.imageData = this.context.getImageData(0, 0, this.width, this.height)
        // 存储本次绘制坐标信息
        this.drawInfo.push({
          x: canvasX / this.width,
          y: canvasY / this.height,
          type: this.lineType
        })
      }
    },
    Area (p0, p1, p2) {
      let area = 0.0
      area = p0.x * p1.y + p1.x * p2.y + p2.x * p0.y - p1.x * p0.y - p2.x * p1.y - p0.x * p2.y
      return area / 2
    },
    // 计算多边形质心
    getPolygonAreaCenter (points) {
      let sumX = 0
      let sumY = 0
      let sumArea = 0
      let p1 = points && points.length > 0 ? points[1] : ''
      for (var i = 2; i < points.length; i++) {
        let p2 = points[i]
        let area = this.Area(points[0], p1, p2)
        sumArea += area
        sumX += (points[0].x + p1.x + p2.x) * area
        sumY += (points[0].y + p1.y + p2.y) * area
        p1 = p2
      }
      return {
        x: sumX / sumArea / 3,
        y: sumY / sumArea / 3
      }
    },
    // 根据坐标信息绘制图形
    drawWithInfo () {
      this.info.forEach(item => {
        this.context.beginPath()
        if (!item.type) {
          // 设置颜色
          this.context.strokeStyle = item.regionColor
          this.context.fillStyle = item.regionColor
          // 绘制多边形的边
          if (typeof item.region === 'string') {
            item.region = JSON.parse(item.region)
          }
          item.region && item.region.length > 0 && item.region.forEach(point => {
            this.context.lineTo(point.x * this.width, point.y * this.height)
          })
          this.context.closePath()
          // 在多边形质心标注文字
          let point = this.getPolygonAreaCenter(item.region)
          this.context.fillText(item.areaName, point.x * this.width, point.y * this.height)
        } else if (item.type === 'rec') {
          this.context.rect(item.x * this.width, item.y * this.height, item.w * this.width, item.h * this.height)
        } else if (item.type === 'circle') {
          this.drawEllipse(this.context, (item.x + item.a) * this.width, (item.y + item.b) * this.height, item.a > 0 ? item.a * this.width : -item.a * this.width, item.b > 0 ? item.b * this.height : -item.b * this.height)
        } else if (item.type === 'line') {
          this.drwaLine(item.x * this.width, item.y * this.height, item.w * this.width, item.h * this.height)
        } else if (this.lineType === 'arrow') {
          this.drawLineArrow(item.x * this.width, item.y * this.height, item.w * this.width, item.h * this.height)
        }
        this.context.stroke()
      })
    },
    // 鼠标移动时绘制
    canvasMove (e) {
      var eva = e || window.event;
      if (this.canvasMoveUse && this.canDraw) {
        // client是基于整个页面的坐标，offset是cavas距离pictureDetail顶部以及左边的距离
        let canvasX = e.clientX - e.target.parentNode.offsetLeft
        let canvasY = e.clientY - e.target.parentNode.offsetTop
        if (this.lineType === 'rec') { // 绘制矩形时恢复起始点状态再重新绘制
          this.context.putImageData(this.beginRec.imageData, 0, 0)
          this.context.beginPath()
          this.context.rect(this.beginRec.x, this.beginRec.y, canvasX - this.beginRec.x, canvasY - this.beginRec.y)
          let info = this.drawInfo[this.drawInfo.length - 1]
          info.w = canvasX / this.width - info.x
          info.h = canvasY / this.height - info.y
        } else if (this.lineType === 'circle') { // 绘制椭圆时恢复起始点状态再重新绘制
          this.context.putImageData(this.beginRec.imageData, 0, 0)
          this.context.beginPath()
          let a = (canvasX - this.beginRec.x) / 2
          let b = (canvasY - this.beginRec.y) / 2
          this.drawEllipse(this.context, this.beginRec.x + a, this.beginRec.y + b, a > 0 ? a : -a, b > 0 ? b : -b)
          let info = this.drawInfo[this.drawInfo.length - 1]
          info.a = a / this.width
          info.b = b / this.height
        } else if (this.lineType === 'line') {
          this.context.putImageData(this.beginRec.imageData, 0, 0)
          this.context.beginPath()
          let a = (canvasX - this.beginRec.x)
          let b = (canvasY - this.beginRec.y)
          this.drwaLine(this.context, this.beginRec.x, this.beginRec.y, canvasX, canvasY)
          let info = this.drawInfo[this.drawInfo.length - 1]
          info.a = a / this.width
          info.b = b / this.height
        } else if (this.lineType === 'arrow') {
          this.context.putImageData(this.beginRec.imageData, 0, 0)
          this.context.beginPath()
          let a = (canvasX - this.beginRec.x)
          let b = (canvasY - this.beginRec.y)
          this.drawLineArrow(this.context, this.beginRec.x, this.beginRec.y, canvasX, canvasY)
          let info = this.drawInfo[this.drawInfo.length - 1]
          info.a = a / this.width
          info.b = b / this.height
        } else if (this.lineType === 'clean') {
          this.context.beginPath()
          var x = eva.offsetX;
          var y = eva.offsetY;
          var w = 50;
          let pxs = this.contextOri.getImageData(x - w / 2, y - w / 2, w, w);
          this.context.putImageData(pxs, x - w / 2, y - w / 2);
        }
        this.context.stroke()
      }
    },
    downloadIamge () {
      let that = this
      html2Canvas(document.getElementById(that.radom), {
        useCORS: true, // 解决canvas跨域
        allowTaint: false
      }).then(function (canvas) {
        // let contentWidth = canvas.width
        // let contentHeight = canvas.height
        // let pageHeight = (contentWidth / 592.28) * 841.89
        // let leftHeight = contentHeight
        // let position = 0
        // let imgWidth = 595.28
        // let imgHeight = (592.28 / contentWidth) * contentHeight
        let pageData = canvas.toDataURL('image/jpeg', 1.0)
        var a = document.createElement('a')
        var event = new MouseEvent('click')
        a.download = 'canvasImg'
        a.href = pageData
        a.dispatchEvent(event)
      })
    },
    // 绘制线条
    drwaLine (context, x, y, a, b) {
      context.beginPath();
      context.moveTo(x, y);
      context.lineTo(a, b);
    },
    // 绘制箭头
    drawLineArrow (context, x, y, a, b) {
      var headlen = 10;//自定义箭头线的长度
      var theta = 45;//自定义箭头线与直线的夹角，个人觉得45°刚刚好
      var arrowX, arrowY;//箭头线终点坐标
      // 计算各角度和对应的箭头终点坐标
      var angle = Math.atan2(y - b, x - a) * 180 / Math.PI;
      var angle1 = (angle + theta) * Math.PI / 180;
      var angle2 = (angle - theta) * Math.PI / 180;
      var topX = headlen * Math.cos(angle1);
      var topY = headlen * Math.sin(angle1);
      var botX = headlen * Math.cos(angle2);
      var botY = headlen * Math.sin(angle2);
      context.beginPath();
      //画直线
      context.moveTo(x, y);
      context.lineTo(a, b);

      arrowX = a + topX;
      arrowY = b + topY;
      //画上边箭头线
      context.moveTo(arrowX, arrowY);
      context.lineTo(a, b);

      arrowX = a + botX;
      arrowY = b + botY;
      //画下边箭头线
      context.lineTo(arrowX, arrowY);
    },
    // 绘制椭圆
    drawEllipse (context, x, y, a, b) {
      context.save()
      var r = (a > b) ? a : b
      var ratioX = a / r
      var ratioY = b / r
      context.scale(ratioX, ratioY)
      context.beginPath()
      context.arc(x / ratioX, y / ratioY, r, 0, 2 * Math.PI, false)
      context.closePath()
      context.restore()
    },
    // 鼠标抬起
    canvasUp (e) {
      if (this.canDraw) {
        this.canvasMoveUse = false
      }
    },
    // 获取坐标信息
    getInfo () {
      return this.drawInfo
    },
    // 清空
    clearDraw () {
      this.context.clearRect(0, 0, this.width, this.height)
      this.contextOri.clearRect(0, 0, this.width, this.height)
      this.clean()
    },
    // 清空画布
    clean () {
      this.context.drawImage(this.img, 0, 0, this.width, this.height)
      this.contextOri.drawImage(this.img, 0, 0, this.width, this.height)
      // var bg = this.context.createPattern(this.img, "no-repeat");//createPattern() 方法在指定的方向内重复指定的元素。
      // this.context.fillStyle = bg;//fillStyle 属性设置或返回用于填充绘画的颜色、渐变或模式。
      // this.context.fillRect(0, 0, this.width, this.height);//绘制已填充矩形fillRect(左上角x坐标, 左上角y坐标, 宽, 高)
      // this.drawInfo = []
      // if (this.info && this.info.length !== 0) this.drawWithInfo()
    }
  }
}
</script>
<style scoped>
.canvas {
  cursor: crosshair;
}
#oriCanvas {
  display: none;
}
input {
  display: none;
  position: absolute;
  left: 0;
  top: 0;
}
</style>
